package com.example.demo.utils;

import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.*;

/**
 * @author cys1731 2020/5/7 15:16
 */
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public class CollectionUtil extends CollectionUtils {

    @SuppressWarnings("all")
    public static <T> void foreach(List<T> list, Consumer<T> action) {
        if (list instanceof ArrayList) {
            for (int i = 0, size = list.size(); i < size; i++) {
                action.accept(list.get(i));
            }
        } else {
            for (T t : list) {
                action.accept(t);
            }
        }
    }

    /**
     * T 为对象， Integer 为当前遍历下标
     */
    public static <T> void foreach(List<T> list, BiConsumer<T, Integer> action) {
        if (list instanceof ArrayList) {
            for (int i = 0, size = list.size(); i < size; i++) {
                action.accept(list.get(i), i);
            }
        } else {
            int i = 0;
            for (T t : list) {
                action.accept(t, i);
                i++;
            }
        }
    }

    /**
     * T 为对象，R 为返回值
     *
     * @param list         集合
     * @param action       每次循环返回值
     * @param compute      对每次循环的返回值的处理，用于叠加计算类型
     * @param resultIfNull 默认值，如果结果null，则返回此默认值
     */
    @SuppressWarnings("all")
    public static <T, R> R foreach(List<T> list, Function<T, R> action, BiFunction<R, R, R> compute, Supplier<R> resultIfNull) {
        if (isEmpty(list)) {
            return resultIfNull.get();
        }
        R r = action.apply(list.get(0));
        if (list instanceof ArrayList) {
            for (int i = 1, size = list.size(); i < size; i++) {
                R r1 = action.apply(list.get(i));
                r = compute.apply(r, r1);
            }
        } else {
            int i = 0;
            for (T t : list) {
                if (i == 0) continue;
                R r1 = action.apply(t);
                r = compute.apply(r, r1);
                i++;
            }
        }
        if (r == null) r = resultIfNull.get();
        return r;
    }

    /**
     * 将map转换为KeyValue对象集合
     */
    public static <K, V> List<KeyValue<K, V>> mapToListKeyValue(Map<K, V> source) {
        List<KeyValue<K, V>> target = new ArrayList<>();
        return mapToListKeyValue(source, target);
    }

    /**
     * 将map转换为KeyValue对象追加到目标集合
     *
     * @param source map
     * @param target 目标集合
     */
    public static <K, V> List<KeyValue<K, V>> mapToListKeyValue(Map<K, V> source, List<KeyValue<K, V>> target) {
        for (Map.Entry<K, V> entry : source.entrySet()) {
            KeyValue<K, V> kv = new KeyValue<>(entry.getKey(), entry.getValue());
            target.add(kv);
        }
        return target;
    }

    /**
     * 将map的key克隆，返回一个同类型的新的map
     *
     * @param source map
     * @param value  新的map的value
     */
    public static <K, V, R> Map<K, R> mapKeyClone(Map<K, V> source, Function<K, R> value) {
        try {
            @SuppressWarnings("unchecked")
            Map<K, R> map = source.getClass().newInstance();
            for (K k : source.keySet()) {
                map.put(k, value.apply(k));
            }
            return map;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("系统异常");
        }
    }

    /**
     * 将map的key克隆，返回一个同类型的新的map
     *
     * @param source map
     * @param value  新的map的value
     */
    public static <K, V, R> LinkedHashMap<K, R> mapKeyClone(LinkedHashMap<K, V> source, Function<K, R> value) {
        LinkedHashMap<K, R> map = new LinkedHashMap<>();
        for (K k : source.keySet()) {
            map.put(k, value.apply(k));
        }
        return map;
    }

    /**
     * 将map的value作为key克隆，返回一个同类型的新的map
     *
     * @param source map
     * @param value  新的map的value
     */
    public static <K, V, R> Map<V, R> mapValueAsKeyClone(Map<K, V> source, Function<V, R> value) {
        try {
            @SuppressWarnings("unchecked")
            Map<V, R> map = source.getClass().newInstance();
            for (V v : source.values()) {
                map.put(v, value.apply(v));
            }
            return map;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("系统异常");
        }
    }

    /**
     * 将map的value作为key克隆，返回一个同类型的新的map
     *
     * @param source map
     * @param value  新的map的value
     */
    public static <K, V, R> LinkedHashMap<V, R> mapValueAsKeyClone(LinkedHashMap<K, V> source, Function<V, R> value) {
        LinkedHashMap<V, R> map = new LinkedHashMap<>();
        for (V v : source.values()) {
            map.put(v, value.apply(v));
        }
        return map;
    }

    /**
     * 将map按条件克隆
     * @param source 源map
     * @param condition 条件
     */
    public static <K, V> LinkedHashMap<K, V> mapConditionClone(Map<K, V> source, BiFunction<K, V, Boolean> condition) {
        LinkedHashMap<K, V> map = new LinkedHashMap<>();
        source.forEach((k, v) -> {
            Boolean b = condition.apply(k, v);
            if (b != null && b) {
                map.put(k, v);
            }
        });
        return map;
    }

    /**
     * 将目标map的value作为此map的key，只在source和target有相同的key时。<br/>
     * 这些改动将只在新返回的Map中生效
     *
     * @param source map
     * @param target 目标map
     */
    public static <K, V, R> LinkedHashMap<V, R> mapKeyFromValue(LinkedHashMap<K, R> source, Map<K, V> target) {
        LinkedHashMap<V, R> map = new LinkedHashMap<>();
        for (Map.Entry<K, R> entry : source.entrySet()) {
            V v = target.get(entry.getKey());
            if (v != null) {
                map.put(target.get(entry.getKey()), entry.getValue());
            }
        }
        return map;
    }

    /**
     * 将Map.size=2的List转换为Map，List.Map的两个value一个作为key，一个作为value
     *
     * @param source MapF2F的集合
     * @param key    新Map的key
     * @param value  新Map的value
     */
    public static <K, V, R1, R2> LinkedHashMap<R1, R2> listMapF2FToMap(List<? extends Map<K, V>> source, Function<V, R1> key, Function<V, R2> value) {
        LinkedHashMap<R1, R2> res = new LinkedHashMap<>(source.size());
        for (Map<K, V> map : source) {
            List<K> list = new ArrayList<>(map.keySet());
            if (list.size() != 2) {
                throw new RuntimeException("格式错误[listMapF2FToMap]");
            }
            V v1 = map.get(list.get(0));
            V v2 = map.get(list.get(1));
            res.put(key.apply(v1), value.apply(v2));
        }
        return res;
    }

    /**
     * 将Map.size=2的List转换为{@code List<KeyValue>}，List.Map的两个value一个作为key，一个作为value
     *
     * @param source MapF2F的集合
     * @param key    KeyValue的key
     * @param value  KeyValue的value
     */
    public static <K, V, R1, R2> List<KeyValue<R1, R2>> listMapF2FToListKeyValue(List<? extends Map<K, V>> source, Function<V, R1> key, Function<V, R2> value) {
        List<KeyValue<R1, R2>> res = new ArrayList<>(source.size());
        for (Map<K, V> map : source) {
            List<K> list = new ArrayList<>(map.keySet());
            if (map.size() != 2) {
                throw new RuntimeException("格式错误[listMapF2FToListKeyValue]");
            }
            V v1 = map.get(list.get(0));
            V v2 = map.get(list.get(1));
            res.add(new KeyValue<>(key.apply(v1), value.apply(v2)));
        }
        return res;
    }

    /**
     * 将source有序转换为另一个List
     *
     * @param source {@code List<T>}
     * @param value {@code List<R>}的内容
     * @return {@code List<R>}
     */
    public static <T, R> List<R> listToList(List<T> source, Function<T, R> value) {
        List<R> res = new ArrayList<R>();
        for (T t : source) {
            res.add(value.apply(t));
        }
        return res;
    }
}
